﻿using Engine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

namespace CommandBlock
{
    /// <summary>
    /// 指令管理 
    /// </summary>
    public class InstructionManager
    {
        public static Dictionary<string, Instruction> FunInstructions = new Dictionary<string, Instruction>();//key=name

        public static Dictionary<string, Instruction> ConInstructions = new Dictionary<string, Instruction>();//key=if:name

        public static List<HistoryEditItem> HistoryEditInstructions = new List<HistoryEditItem>();

        public static List<HistoryEditItem> CollectionInstructions = new List<HistoryEditItem>();

        public static void Initialize()
        {
            foreach (ContentInfo contentInfo in ContentManager.List())
            {
                if (contentInfo.Filename.StartsWith("InstructionsDoc"))
                {
                    string text = string.Empty;
                    try
                    {
                        text = ContentManager.Get<string>(contentInfo.Filename.Split(new char[] { '.' })[0]);
                    }
                    catch
                    {
                    }
                    if (!string.IsNullOrEmpty(text))
                    {
                        string[] classify = text.Split(new char[1] { '#' });
                        if (classify != null && classify.Length > 8)
                        {
                            SetInstructions(classify[2], classify[4], false);
                            SetInstructions(classify[6], classify[8], true);
                        }
                    }
                }
            }
            LoadHistoryItems();
            SetMoreOptions();
        }

        public static Instruction GetInstruction(string name, bool iscon)
        {
            if (!iscon)
            {
                if (FunInstructions.TryGetValue(name, out Instruction value))
                {
                    return value;
                }
            }
            else
            {
                if (ConInstructions.TryGetValue("if:" + name, out Instruction value))
                {
                    return value;
                }
            }
            Log.Error("InstructionManager:找不到" + name + "指令的定义");
            return null;
        }

        public static string GetDisplayName(string name)
        {
            if (!name.Contains(":")) name = "cmd:" + name;
            return name.Split(new char[1] { ':' })[1];
        }

        public static string GetCommandType(string name, bool iscon, string type)
        {
            Instruction instruction = GetInstruction(name, iscon);
            if (instruction != null && instruction.Types.Contains(type)) return type;
            return "default";
        }

        public static string GetInstructionDemo(string name, string type, bool iscon)
        {
            Instruction instruction = GetInstruction(name, iscon);
            if (instruction != null && instruction.Demos.TryGetValue(type, out string value))
            {
                return value;
            }
            return string.Empty;
        }

        public static string GetInstructionDetail(string name, string type, bool iscon)
        {
            Instruction instruction = GetInstruction(name, iscon);
            if (instruction != null && instruction.Details.TryGetValue(type, out string value))
            {
                Regex regex = new Regex(@"\((.+)\)");
                string definition = regex.Match(value).Value;
                if (!string.IsNullOrEmpty(definition))
                {
                    return value.Replace(definition, "");
                }
                else
                {
                    return value;
                }
            }
            return "暂无";
        }

        public static string[] GetInstructionOption(string name, string type, string para, bool iscon)
        {
            Instruction instruction = GetInstruction(name, iscon);
            if (instruction != null && instruction.Options.TryGetValue(type + "$" + para, out string value))
            {
                return value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            }
            return null;
        }

        public static string GetParameterName(string name, string type, string para, bool iscon)
        {
            Instruction instruction = GetInstruction(name, iscon);
            if (instruction != null)
            {
                foreach (var v in instruction.Definitions)
                {
                    if (type + "$" + para == v.Key) return v.Value;
                }
                if (para.StartsWith("text")) return "文本信息" + para.Replace("text", "");
                else if (para.StartsWith("color")) return "颜色" + para.Replace("color", "");
                else if (para.StartsWith("pos")) return "坐标" + para.Replace("pos", "");
                else if (para.StartsWith("eyes")) return "视角" + para.Replace("eyes", "");
                else if (para.StartsWith("id")) return "方块值" + para.Replace("id", "");
                else if (para.StartsWith("fid")) return "家具序号" + para.Replace("fid", "");
                else if (para.StartsWith("cid")) return "衣物序号" + para.Replace("cid", "");
                else if (para.StartsWith("obj")) return "生物对象" + para.Replace("obj", "");
                else if (para.StartsWith("con")) return "开闭" + para.Replace("con", "");
                else return "请输入值";
            }
            return "未知属性";
        }

        public static bool IsFixedParameter(string para)
        {
            return (para == "cmd" || para == "if" || para == "type" || para == "cd");
        }

        public static bool IsInvalidOption(string value, string name, string type, string para, bool iscon)
        {
            string[] options = GetInstructionOption(name, type, para, iscon);
            if (options != null)
            {
                foreach (string option in options)
                {
                    if (option.Contains(":"))
                    {
                        if (value == option.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0].Replace(" ", ""))
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (value == option)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public static Dictionary<string, Instruction> GetSurvivalList(Dictionary<string, Instruction> instructions)
        {
            Dictionary<string, Instruction> surInstructions = new Dictionary<string, Instruction>();
            foreach (string key in instructions.Keys)
            {
                if (instructions[key].Survival)
                {
                    surInstructions.Add(key, instructions[key]);
                }
            }
            return surInstructions;
        }

        public static void SetInstructions(string classify1, string classify2, bool iscon)
        {
            Dictionary<string, Instruction> Instructions = iscon ? ConInstructions : FunInstructions;
            string funAbout = classify1.Replace("\n", "#");
            string[] arfunAbout = funAbout.Split(new char[1] { '#' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string line in arfunAbout)
            {
                if (line.StartsWith("//")) continue;
                string[] words = line.Split(new char[1] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                if (words != null && words.Length == 2)
                {
                    if (!Instructions.TryGetValue(words[0], out Instruction instruction))
                    {
                        instruction = new Instruction();
                        instruction.Name = words[0];
                        instruction.About = words[1].Replace("*", "");
                        instruction.Survival = !words[1].Contains("*");
                        instruction.Condition = iscon;
                        if (!instruction.Condition)
                        {
                            FunInstructions[instruction.Name] = instruction;
                        }
                        else
                        {
                            ConInstructions[instruction.Name] = instruction;
                        }
                    }
                    else
                    {
                        instruction.Name = words[0];
                        instruction.About = words[1].Replace("*", "");
                        instruction.Survival = !words[1].Contains("*");
                    }
                }
            }

            string funDefinition = classify2.Replace("\n", "#");
            string[] arfunDefinition = funDefinition.Split(new char[1] { '#' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string line in arfunDefinition)
            {
                if (line.StartsWith("//")) continue;
                string[] words = line.Split(new char[1] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                if (words != null && words.Length >= 2)
                {
                    string[] word = words[0].Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (!Instructions.TryGetValue(word[0], out Instruction instruction))
                    {
                        instruction = new Instruction();
                        instruction.Name = word[0];
                        instruction.About = "暂无相关说明";
                        instruction.Condition = iscon;
                        instruction.Survival = true;
                        if (!instruction.Condition)
                        {
                            FunInstructions[instruction.Name] = instruction;
                        }
                        else
                        {
                            ConInstructions[instruction.Name] = instruction;
                        }
                    }
                    string type = word[1].Split(new char[1] { ':' })[1];
                    instruction.Types.Add(type);
                    instruction.Demos.Add(type, words[0]);
                    instruction.Details.Add(type, words[1]);
                    string[] paras = new string[word.Length - 2];
                    for (int i = 0; i < word.Length - 2; i++)
                    {
                        paras[i] = word[i + 2].Split(new char[1] { ':' })[0];
                    }
                    instruction.Paras.Add(type, paras);
                    Regex regex = new Regex(@"\((.+)\)");
                    string defparas = regex.Match(words[1]).Value;
                    if (!string.IsNullOrEmpty(defparas))
                    {
                        defparas = defparas.Substring(1, defparas.Length - 2);
                        string[] defpara = defparas.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string def in defpara)
                        {
                            Point2 valueRange = Point2.Zero;
                            string deftemp = def;
                            Regex regex2 = new Regex(@"\[(.+)\]");
                            string defrange = regex2.Match(def).Value;
                            if (!string.IsNullOrEmpty(defrange))
                            {
                                deftemp = deftemp.Replace(defrange, "");
                                defrange = defrange.Substring(1, defrange.Length - 2);
                                string[] range = defrange.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                if (range.Length == 2)
                                {
                                    valueRange = new Point2(int.Parse(range[0]), int.Parse(range[1]));
                                }
                            }
                            string[] ardeftemp = deftemp.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
                            if (ardeftemp.Length == 2)
                            {
                                string type_v = type + "$" + ardeftemp[0];
                                instruction.Definitions.Add(type_v, ardeftemp[1]);
                                if (valueRange != Point2.Zero)
                                {
                                    instruction.Ranges.Add(type_v, valueRange);
                                }
                            }
                        }
                    }
                    if (words.Length > 2)
                    {
                        string temp = words[2].Replace("\r", "");
                        string[] parasOptions = temp.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string paraOption in parasOptions)
                        {
                            string[] arParaOption = paraOption.Split(new char[1] { '@' }, StringSplitOptions.RemoveEmptyEntries);
                            string type_v = type + "$" + arParaOption[0];
                            instruction.Options.Add(type_v, arParaOption[1]);
                        }
                    }
                }
            }
        }

        public static void AddHistoryItem(HistoryEditItem historyEditItem)
        {
            if (historyEditItem == null) return;
            if (HistoryEditInstructions.Count > 0)
            {
                HistoryEditItem lastHistoryEditItem = HistoryEditInstructions[HistoryEditInstructions.Count - 1];
                if (lastHistoryEditItem.Line == historyEditItem.Line && lastHistoryEditItem.Collection == historyEditItem.Collection)
                {
                    HistoryEditInstructions[HistoryEditInstructions.Count - 1] = historyEditItem;
                }
                else
                {
                    HistoryEditInstructions.Add(historyEditItem);
                }
            }
            else
            {
                HistoryEditInstructions.Add(historyEditItem);
            }
            if (historyEditItem.Collection)
            {
                foreach (var h in CollectionInstructions)
                {
                    if (h.Line == historyEditItem.Line)
                    {
                        CollectionInstructions.Remove(h);
                        break;
                    }
                }
                CollectionInstructions.Add(historyEditItem);
            }
        }

        public static void RemoveHistoryItem(HistoryEditItem historyEditItem)
        {
            if (historyEditItem == null) return;
            if (CollectionInstructions.Contains(historyEditItem))
            {
                CollectionInstructions.Remove(historyEditItem);
            }
            if (HistoryEditInstructions.Contains(historyEditItem))
            {
                HistoryEditInstructions.Remove(historyEditItem);
            }
        }

        public static void LoadHistoryItems()
        {
            string historyItemPath = Storage.CombinePaths(DataHandle.GetCommandPath(), "HistoryEditItems.txt");
            Stream stream = Storage.OpenFile(historyItemPath, OpenFileMode.CreateOrOpen);
            StreamReader streamReader = new StreamReader(stream);
            string line = string.Empty;
            while ((line = streamReader.ReadLine()) != null)
            {
                string[] stritems = line.Split(new char[1] { '#' }, StringSplitOptions.RemoveEmptyEntries);
                if (stritems.Length >= 6)
                {
                    HistoryEditItem historyEditItem = new HistoryEditItem();
                    historyEditItem.About = stritems[0];
                    historyEditItem.Line = stritems[1];
                    historyEditItem.Position = DataHandle.GetPoint3Value(stritems[2]);
                    historyEditItem.Pass = (stritems[3] == "True");
                    historyEditItem.Condition = (stritems[4] == "True");
                    historyEditItem.Collection = (stritems[5] == "True");
                    AddHistoryItem(historyEditItem);
                }
            }
            stream.Dispose();
        }

        public static void SaveHistoryItems()
        {
            string historyItemPath = Storage.CombinePaths(DataHandle.GetCommandPath(), "HistoryEditItems.txt");
            Stream stream = Storage.OpenFile(historyItemPath, OpenFileMode.Create);
            using (StreamWriter streamWriter = new StreamWriter(stream))
            {
                foreach (HistoryEditItem item in HistoryEditInstructions)
                {
                    string line = string.Format("{0}#{1}#{2}#{3}#{4}#{5}", item.About.Replace("\r", ""), item.Line, item.Position.ToString(), item.Pass.ToString(), item.Condition.ToString(), item.Collection.ToString());
                    streamWriter.WriteLine(line);
                }
                streamWriter.Flush();
            }
            stream.Dispose();
        }

        public static void SetMoreOptions()
        {
            Instruction instruction = GetInstruction("texture", false);
            if (instruction != null)
            {
                string line = string.Empty;
                foreach (EntityInfo entityInfo in EntityInfoManager.EntityInfos.Values)
                {
                    if (entityInfo.KeyName == "boat") continue;
                    line += entityInfo.Texture.Replace("Textures/Creatures/", "") + ":" + entityInfo.DisplayName + ",";
                }
                instruction.Options.Add("pakcreature$opt", line);
            }
            Instruction instruction2 = GetInstruction("audio", false);
            if (instruction2 != null)
            {
                string line = string.Empty;
                foreach (ContentInfo contentInfo in ContentManager.List())
                {
                    if (contentInfo.ContentPath.StartsWith("Audio/"))
                    {
                        line += contentInfo.ContentPath.Replace("Audio/", "") + ",";
                    }
                }
                instruction2.Options.Add("contentpak$opt", line);
            }
            Instruction instruction3 = GetInstruction("model", false);
            if (instruction3 != null)
            {
                string line = string.Empty;
                foreach (ContentInfo contentInfo in ContentManager.List())
                {
                    if (contentInfo.ContentPath.StartsWith("Models/"))
                    {
                        line += contentInfo.ContentPath.Replace("Models/", "") + ",";
                    }
                }
                instruction3.Options.Add("pakmodel$opt", line);
            }
        }
    }
}